import os

from appium.webdriver.common.mobileby import MobileBy as By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import yaml
from string import Template
import time

from py_page.app import App
from common.log import Logger
from common.handle_black import *

logging = Logger(__name__).get_logger()
class BasePage(App):

    @handle_black
    def find(self, by, locator):
        by_locator = None
        if by == 'id' or by == 'ID':
            by_locator = (By.ID, locator)
        elif by == 'xpath' or by == 'XPATH':
            by_locator = (By.XPATH, locator)
        elif by == 'class' or by == 'CLASS':
            by_locator = (By.CLASS_NAME, locator)
        elif by == 'ACCESSIBILITY_ID' or by == 'accessibility_id':
            by_locator = (By.ACCESSIBILITY_ID, locator)
        ele = WebDriverWait(self.driver, 5).until(EC.visibility_of_element_located(by_locator), message='页面未找到元素超时')
        #ele = self.driver.find_element(*by_locator)
        return ele

    @handle_black
    def finds(self, by, locator):
        by_locator = None
        if by == 'id' or by == 'ID':
            by_locator = (By.ID, locator)
        elif by == 'xpath' or by == 'XPATH':
            by_locator = (By.XPATH, locator)
        elif by == 'class' or by == 'CLASS':
            by_locator = (By.CLASS_NAME, locator)
        elif by == 'ACCESSIBILITY_ID' or by == 'accessibility_id':
            by_locator = (By.ACCESSIBILITY_ID, locator)
        eles = WebDriverWait(self.driver, 5).until(EC.visibility_of_all_elements_located(by_locator), message='页面未找到元素超时')
        #eles = self.driver.find_elements(*by_locator)
        return eles

    @handle_black
    def find_and_click(self, by, locator):
        self.find(by, locator).click()

    @handle_black
    def find_and_send(self, by, locator, text):
        self.find(by, locator).send_keys(text)

    @handle_black
    def find_and_clear(self,by, locator):
        self.find(by, locator).clear()

    @handle_black
    def finds_and_click(self,by, locator, index):
        eles= self.finds(by, locator)
        eles(index).click()

    @handle_black
    def finds_and_send(self,by, locator, index, text):
        eles = self.finds(by, locator)
        eles(index).send_keys(text)

    @handle_black
    def finds_and_clear(self,by, locator, index):
        eles = self.finds(by, locator)
        eles(index).clear()

    def swipe_up(self, scale=0.5, t=500, n=1):
        '''
        向上滑动屏幕
        :param scale: 滑动距离，即屏幕高度的百分比
        :param t:  滑动持续时间，单位毫秒
        :param n:  滑动次数
        :return: None
        '''
        l = self.driver.get_window_size()
        print(f"窗口size:{l}")
        x = l['width'] * 0.5
        y1 = l['height'] * (1 + scale) * 0.5
        y2 = l['height'] * (1 - scale) * 0.5
        for i in range(n):
            self.driver.swipe(x, y1, x, y2, t)

    def swipe_down(self, scale=0.5, t=500, n=1):
        '''
        向下滑动屏幕
        :param scale: 滑动距离，即屏幕高度的百分比
        :param t:  滑动持续时间，单位毫秒
        :param n:  滑动次数
        :return: None
        '''
        l = self.driver.get_window_size()
        x = l['width'] * 0.5
        y1 = l['height'] * (1 - scale) * 0.5
        y2 = l['height'] * (1 + scale) * 0.5
        for i in range(n):
            self.driver.swipe(x, y1, x, y2, t)

    def swipe_left(self, scale=0.5, t=500, n=1):
        '''
        向左滑动屏幕
        :param scale: 滑动距离，即屏幕宽度的百分比
        :param t:  滑动持续时间，单位毫秒
        :param n:  滑动次数
        :return: None
        '''
        l = self.driver.get_window_size()
        x1 = l['width'] * (1 + scale) * 0.5
        y = l['height'] * 0.5
        x2 = l['width'] * (1 - scale) * 0.5
        for i in range(n):
            self.driver.swipe(x1, y, x2, y, t)

    def swipe_right(self, scale=0.5, t=500, n=1):
        '''
        向右滑动屏幕
        :param scale: 滑动距离，即屏幕宽度的百分比
        :param t:  滑动持续时间，单位毫秒
        :param n:  滑动次数
        :return: None
        '''
        l = self.driver.get_window_size()
        x1 = l['width'] * (1 - scale) * 0.5
        y = l['height'] * 0.5
        x2 = l['width'] * (1 + scale) * 0.5
        for i in range(n):
            self.driver.swipe(x1, y, x2, y, t)

    def run_steps(self, yaml_path, operation, **kwargs):
        '''
        对yaml_page中页面元素进行读取，并进行模板匹配kwargs参数，根据yaml中的action进行对元素的相关操作
        :param yaml_path: yaml_page中对应page的文件地址
        :param operation: 对应yaml中的行为标题
        :param kwargs: 传入的一个入参数字典，用于模板匹配
        :return: 一个ele对象
        '''

        with open(yaml_path, "r", encoding="UTF-8") as f:
            datas = yaml.safe_load(f)
            list_steps = datas[operation]
            yaml_steps = yaml.dump(list_steps)
            if kwargs:
                for k in kwargs.keys():  # 对传入参数数据类型为字符串的进行处理，防止模板匹配与yaml转换被转换成非字符串类型
                    if isinstance(kwargs[k], str):
                        kwargs[k] = f"'{kwargs[k]}'"
                temp_steps = Template(yaml_steps).substitute(kwargs)
                steps = yaml.safe_load(temp_steps)
            else:
                steps = yaml.safe_load(yaml_steps)
            for step in steps:
                sleep_time = step.get('sleep')  # 如果字典中没有这个key，通过get(key)-> None
                if sleep_time:
                    time.sleep(sleep_time)
                action = step["action"]
                if action == "find_and_click":
                    try:
                        self.find_and_click(*step["locator"])
                    except BaseException as e:
                        logging.info(f'{yaml_path}:{action}:{step["locator"]}元素定位异常，错误信息：{e}')
                        raise e
                elif action == "find_and_send":
                    try:
                        self.find_and_send(*step["locator"], step['text'])
                    except BaseException as e:
                        logging.info(f'{yaml_path}:{action}:{step["locator"]}元素定位异常，错误信息：{e}')
                        raise e

                elif action == "find_and_clear":
                    try:
                        self.find_and_clear(*step["locator"])
                    except BaseException as e:
                        logging.info(f'{yaml_path}:{action}:{step["locator"]}元素定位异常，错误信息：{e}')
                        raise e
                elif action == "finds":
                    try:
                        ele = self.finds(*step["locator"])
                        return ele
                    except BaseException as e:
                        logging.info(f'{yaml_path}:{action}:{step["locator"]}元素定位异常，错误信息：{e}')
                        raise e
                elif action == "finds_and_click":
                    try:
                        self.finds_and_click(*step["locator"], index=step['index'])
                    except BaseException as e:
                        logging.info(f'{yaml_path}:{action}:{step["locator"]}元素定位异常，错误信息：{e}')
                        raise e
                elif action == "finds_and_send":
                    try:
                        self.finds_and_send(*step["locator"], index=step['index'], text=step['text'])
                    except BaseException as e:
                        logging.info(f'{yaml_path}:{action}:{step["locator"]}元素定位异常，错误信息：{e}')
                        raise e
                elif action == "find":
                    try:
                        ele = self.find(*step["locator"])
                        return ele
                    except Exception as e:
                        logging.info(f'{yaml_path}:{action}:{step["locator"]}元素定位异常，错误信息：{e}')
                        raise e


    @staticmethod
    def get_path(relative_path):
        '''
        文件的路径拼接，返回一个绝对路径
        :param relative_path: 文件的相对路径
        :return: 文件的绝对路径
        '''
        file_path = os.path.abspath(__file__)
        dir_path = os.path.split(file_path)[0]
        far_path = os.path.dirname(dir_path)
        path = far_path + relative_path
        return path
